TCP三次握手中第三次握手时ACK丢失怎么办

本文详细介绍了TCP的三次握手和四次挥手过程,以及在第三次握手时服务器如何处理ACK丢失的情况。讨论了为何需要三次握手而非两次,并分析了服务器在半连接队列中如何应对SYN攻击,包括SYNcookie技术和调整队列参数的方法。此外,还阐述了Linux系统中TCP连接队列的相关参数设置。
摘要由CSDN通过智能技术生成

一、三次握手四次挥手流程 

二、第三次握手时ACK丢失? 

1、Server 端

    第三次的ACK在网络中丢失,那么Server 端该TCP连接的状态为SYN_RCVD,此时server把这个连接会进入到半连接队列,分配内存,并且会根据 TCP的超时重传机制,会等待3秒、6秒、12秒后重新发送SYN+ACK包向客户端,以便Client重新发送ACK包。

    而Server重发SYN+ACK包的次数,可以通过设置/proc/sys/net/ipv4/tcp_synack_retries修改,默认值为5.

TCP 半连接队列(Half-Open Connection Queue)

是指处于半连接状态的 TCP 连接在服务器端等待确认的队列。在 TCP 的三次握手过程中,当服务器接收到客户端的 SYN(同步)包后,服务器会进入半连接状态,并向客户端发送 SYN-ACK(同步-确认)包。此时,服务器端的连接处于半打开状态,等待客户端的最终确认 ACK(确认)包。

半连接队列中存储的是那些已经发送了 SYN-ACK 包,但还没有收到客户端最终确认的连接。这个队列的存在是为了确保服务器能够跟踪和管理这些半打开的连接,以便在合理的时间内得到客户端的确认,或者在超时后及时清理资源,并从半连接队列移除。

2、Client端

    在linux c 中,client 一般是通过 connect() 函数来连接服务器的,而connect()是在 TCP的三次握手的第二次握手完成后就成功返回值。client在接收到SYN+ACK包,client的TCP连接状态就为 established(已连接)表示该连接已经建立,但是服务端还没建立全连接。

如果在第三次握手中的ACK包丢失的情况下,客户端会尝试重新发送第三个ACK包,以确保服务器收到。通常,客户端会在超时后触发重传,避免长时间等待,如果达到最大尝试次数而仍未成功建立连接,客户端可能会放弃建立连接,关闭套接字,并可能通知上层应用连接建立失败。

在重试的过程中,如果server端已经因为半连接队列超时问题,会把这个连接从半连接队列中移除,如果此时server端收到客户端的ack,server端将以RST包响应(用于强制关闭tcp连接),方能感知到Server的错误。

client端接收到服务端发送SYN+ACK包,会尝试发送ACK包进行重连,如果服务端收到ack并且半连接队列中包含此连接,server会把这个连接放入全连接队列(Fully Established Connections Queue

第三次握手时server具体的处理方式

关于TCP全连接队列和半连接队列

场景1:当全连接未满

当server收到client的ack后会先判断全连接队列(Fully Established Connections Queue)是否已满,如果队列未满则从半连接队列移出并存放入全连接队列中,之后服务端accept()处理此请求。

场景2:当全连接已满且tcp_abort_on_overflow = 0

server会扔掉client 发过来的ack。之后隔一段时间server会重发握手第二步的syn+ack包给client,如果客户端连接一直排队不上等待超时则会报超时异常。

场景3:全连接已满且tcp_abort_on_overflow = 1时

server会发送一个RST包给client,表示废除这个握手过程和这个连接(客户端会报connection reset by peer异常)

RST(Reset)包是TCP协议中的一种控制报文,用于终止连接或表示错误, 当一方收到另一方发来的RST包时,它会立即关闭连接,不经过正常的连接关闭阶段。RST包的接收端不会执行连接的正常关闭流程,而是直接关闭连接并释放相关资源。

三、为什么要三次握手,而不是二次握手?

     1、为了避免已失效的连接报文段又到达可服务器。考虑这样一个正常的情况:

   假设TCP连接是两次握手。当客户端发送了一个请求SYN的报文时,由于网络原因这个报文丢失了,那么客户端一段时间内没有收到服务器的确认就会再次发送请求连接报文,这次服务器收到了,双方都建立了连接,然后数据传输,最后关闭连接。但是考虑一下,上文中的丢失SYN数据包若没有丢失,只是在一个网络节点长时间滞留了,这时双方都已经关闭了连接,此时服务器又收到了丢掉了的数据包请求,认为客户端又要建立连接,因为是两次握手所以服务器向客户端发送了确认报文,并变为建立连接状。

     2、避免建立多个链接

       当客户端发送了一个请求SYN的报文时,由于网络波动,此时没有到达服务端,而客户端又重新发送一个SYN包数据,此时网络正常,这两次数据都正常到达server端,此时server端会确认并建立两个连接,这就浪费了服务器的资源。

       如果是三次握手,客户端接收到服务端发送的SYN+ACK包,会选择第二个建立连接,发送一个ACK包给服务端,这是服务端会建立连接并从半连接队列移除,而第一个SYN包一直未收到客户端的ACK包,服务端会从半连接队列移除,这也是导致Server端易受到SYN攻击的原因。

Server端易受到SYN攻击的原因:

     服务器端的资源分配是在二次握手时分配的,而客户端的资源是在完成三次握手时分配的,所以服务器容易受到SYN洪泛攻击,SYN攻击就是Client在短时间内伪造大量不存在的IP地址,并向Server不断地发送SYN包,Server则回复SYN+ACK确认包,并等待Client确认回复ACK,而这些大量的IP是不存在的,并不会向服务端发送ack确认包,所以会大量的占领半连接队列资源,导致正常的SYN请求因为半连接队列满而被丢弃,从而引起网络拥塞甚至系统瘫痪。

四、预防SYN攻击? 

1、开启SYN cookie技术

2、调整最大半连接数

3、调整缩短半连接超时时间

  1. SYN Cookie 机制和半连接队列:

    • 常规情况下: 在典型的 TCP 握手过程中,服务器会将收到的 SYN 包加入半连接队列,并为连接分配资源。只有在完成三次握手后,连接才被认为是完全建立的。
    • 启用 SYN Cookie: 当启用 SYN Cookie 时,服务器在收到 SYN 包时不会在内存中为连接分配资源,而是使用 SYN Cookie 生成一个特殊的标识,发送给客户端。因此,半连接队列在 SYN Cookie 模式下的作用被减弱或完全消除。
  2. SYN Cookie 的生成和验证:

    • 生成: SYN Cookie 是通过对 SYN 请求的信息进行哈希计算得到的。这个计算生成的值即为 SYN Cookie。
    • 验证: 当客户端发送 ACK 包时,携带之前服务器生成的 SYN Cookie。服务器再次计算 SYN Cookie,如果计算结果与客户端发送的 SYN Cookie 匹配,服务器会根据匹配的信息建立连接。
  3. 半连接队列的减轻:

    • 常规模式: 在传统的三次握手模式下,服务器需要在半连接队列中保存连接的状态,等待客户端的最终确认。这可能导致半连接队列耗尽,尤其在面对 SYN 攻击时。
    • 启用 SYN Cookie: SYN Cookie 机制将连接的状态信息保存在客户端,服务器在接收 SYN 请求时不需要分配资源,减轻了半连接队列的负担,避免了 SYN 攻击可能导致的资源耗尽问题。

 五、半、全连接队列值

Linux:

  • 在 Linux 中,TCP连接队列大小由两个参数控制:net.core.somaxconnnet.ipv4.tcp_max_syn_backlog
  • net.core.somaxconn 表示全连接队列的最大大小。
  • net.ipv4.tcp_max_syn_backlog 表示半连接队列(SYN队列)的最大大小。
  • 默认值可能因Linux发行版和版本而异。

在 Linux 系统上,你可以使用 sysctl 命令查看和修改内核参数。具体来说,要查看 net.core.somaxconnnet.ipv4.tcp_max_syn_backlog 的值,可以按照以下步骤进行:

  1. 查看 net.core.somaxconn 的值:

    sysctl net.core.somaxconn

    这会显示 net.core.somaxconn 的当前值。该参数表示全连接队列(已完成连接队列)的最大大小。

  2. 查看 net.ipv4.tcp_max_syn_backlog 的值:

    sysctl net.ipv4.tcp_max_syn_backlog

    这会显示 net.ipv4.tcp_max_syn_backlog 的当前值。该参数表示半连接队列(SYN 队列)的最大大小。

如果你希望永久修改这些参数的值,你可以编辑 /etc/sysctl.conf 文件,添加或修改相应的行,然后运行 sysctl -p 命令来应用更改。例如:

# 修改 net.core.somaxconn
echo "net.core.somaxconn = 65535" >> /etc/sysctl.conf

# 修改 net.ipv4.tcp_max_syn_backlog
echo "net.ipv4.tcp_max_syn_backlog = 65535" >> /etc/sysctl.conf

# 应用更改
sysctl -p

这里的值 65535 是一个示例,你可以根据实际需求设置合适的大小。修改这些参数的值可能需要超级用户权限。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值